package player;

import gui.mainGui;

import java.io.*;
import java.net.*;
import netPacks.message;

public class clientToServer extends Thread{
	
    int DEFAULT_PORT = 5000;
	int port = 0;
    public ObjectInputStream ois = null;
    public ObjectOutputStream oos = null;
    InetAddress serverHostIp = null;
    InetAddress backupHostIp = null;
    Socket clientSocket = null;
    message incoming = new message();
    pinger p = pinger.getInstance();
    
    
    private static volatile clientToServer instance = null;
    
    public static clientToServer getInstance() {
        if (instance == null){
            synchronized (clientToServer.class){
                    if (instance == null){
                        instance = new clientToServer();
                    }
        }}
        return instance;
    }
    
    public clientToServer(){}
	
	public synchronized void run(){
            
    	if(this.port == 0 && player.getInstance().getLatestPort() == 0){
    		this.port = DEFAULT_PORT;
    		player.getInstance().setLatestPort(DEFAULT_PORT);
    	}
    	else if(this.port == 0 && player.getInstance().getLatestPort() != 0){
    		this.port = player.getInstance().getLatestPort();
    	}
    	else if(this.port != 0){
    		player.getInstance().setLatestPort(this.port);
    	}
		
			try{
            	System.out.println("creating client socket...");
            	clientSocket = new Socket(this.serverHostIp , this.port);
            }
            catch(IOException e){
                System.err.println("Cannot open socket to Host "+serverHostIp+" on port "+port+"\n"+e.getMessage());
                System.err.println("Check the physical connections and stuff...");
                player.getInstance().connection = null;
                this.closeConnection();
                mainGui.getInstance().changeServerConButtonStat(true);
                return;
            }
            
            try{
            	System.out.println("Opening input/output streams...");
            	oos = new ObjectOutputStream(clientSocket.getOutputStream());
            	oos.flush();
            	ois = new ObjectInputStream(clientSocket.getInputStream());
                System.out.println("I/O streams opened...");
            }
            catch(IOException e){
                System.err.println("Cannot open I/O streams \n"+e.getMessage());
            }
            System.out.println("Waiting for server messages...");
            gui.mainGui.getInstance().changeReadyButtonStat(true);
            while (true){
                if(!player.getInstance().matched && !player.getInstance().pingerFailFlag){
                	try{
            			netPacks.message tmp = (message) ois.readObject();
                        msgHandler.getInstance().msgQ.add(tmp);
                    }
                    catch(ClassNotFoundException e){
                        System.err.println("Cannot find incoming object Class:\n" + e.getMessage());
                    }
                    catch(IOException e){
                        System.err.println("Cannot read input object from socket. "+"\n"+e.getMessage());
                        e.printStackTrace();
                        this.closeConnection();
                        break;
                    }
                    if(pinger.getInstance().getState().toString() == "NEW"){
                    	pinger.getInstance().start();
                    }
                }
                else{
                	this.closeConnection();
                	System.out.println("Closing connection...");
                	break;
                }
            }
        }
	public void closeConnection(){
		
		if(this.clientSocket != null){
			try{
				this.ois.close();
				this.oos.close();
				this.clientSocket.close();
			}
	        catch(IOException e){
	            System.err.println("cannot close the server connection. \n"+e.getMessage());
	        }
		}
		this.clientSocket = null;
		this.ois = null;
		this.oos = null;
		this.serverHostIp = null;
		clientToServer.instance = null;
	}
	
	public void setServerHost(InetAddress serverHost){
		this.serverHostIp = serverHost;
	}
	
	public InetAddress getServerHost(){
		return this.serverHostIp;
	}
	
	public void setBackupHost(InetAddress backupHost){
		this.backupHostIp = backupHost;
	}
	
	public InetAddress getBackupHost(){
		return this.backupHostIp;
	}
	
	public void setPort(int port){
		this.port = port;
	}
	
	public int getPort(){
		return this.port;
	}
}